#pragma once

#include <coroutine>

namespace co_async {

class PreviousAwaiter {
public:
  PreviousAwaiter(std::coroutine_handle<> previous) : m_previous(previous){};

  // 结果为false，则暂停协程并调用 awaiter.await_suspend(handle)
  bool await_ready() const noexcept { return false; };

  // 1. 如果 await_suspend 返回
  // void，那么立即将控制返回给当前协程的调用方/恢复方（此协程保持暂停），否则
  // 2. 如果 await_suspend 返回 bool，那么：
  // - 值为 true 时将控制返回给当前协程的调用方/恢复方。
  // - 值为 false 时恢复当前协程。
  // 3. 如果 await_suspend 返回某个其他协程的协程句柄，那么（通过调用
  // handle.resume()）恢复该句柄（注意这可以连锁进行，并最终导致当前协程恢复）。
  // 4. 如果 await_suspend 抛出异常，那么捕捉该异常，恢复协程，并立即重抛异常。
  std::coroutine_handle<>
  await_suspend(std::coroutine_handle<> current) const noexcept {
    if (m_previous) {
      return m_previous;
    }
    return std::noop_coroutine();
  }
  void await_resume() const noexcept {}

private:
  std::coroutine_handle<> m_previous;
};

class PreviousPromise {
public:
  auto get_return_object() noexcept {
    return std::coroutine_handle<PreviousPromise>::from_promise(*this);
  }
  // 协程开始执行时调用并 co_await 它的结果。suspend_always 始终暂停
  auto initial_suspend() noexcept { return std::suspend_always{}; }

  // 协程抵达 co_return 时, 调用并 co_await 它的结果
  auto final_suspend() noexcept { return PreviousAwaiter{m_previous}; }

  // 对于 co_return expr;其中 expr 具有非 void 类型时，调用
  // promise.return_value(expr)
  void return_value(std::coroutine_handle<> previous) noexcept {
    m_previous = previous;
  }

  void unhandled_exception() {}

private:
  std::coroutine_handle<> m_previous;
  PreviousPromise &operator=(PreviousPromise &&) = delete;
};
} // namespace co_async